package com.cml.learn.netty.http.server;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.EndOfDataDecoderException;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDecoderException;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
import io.netty.util.AttributeKey;

public class HttpServerInboundHandler extends ChannelInboundHandlerAdapter {

	HttpPostRequestDecoder decoder = null;
	private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // Disk

	public HttpServerInboundHandler() {
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		HttpRequest request = null;
		if (msg instanceof HttpRequest) {
			request = (HttpRequest) msg;

			URI uri = new URI(request.uri());
			if (uri.getPath().equals("/favicon.ico")) {
				return;
			}
			System.out.println("HttpRequest Uri:" + uri + "," + request.method().name());

			String cookie = request.headers().get(HttpHeaderNames.COOKIE);
			System.out.println(cookie);

			if (null != cookie) {
				Cookie cookies = ClientCookieDecoder.STRICT.decode(cookie);
				System.out.println("cookies==>" + cookies);
			}

			QueryStringDecoder decoderQuery = new QueryStringDecoder(uri);
			Map<String, List<String>> uriAttributes = decoderQuery.parameters();
			for (Entry<String, List<String>> attr : uriAttributes.entrySet()) {
				for (String attrVal : attr.getValue()) {
					System.out.println("URI==============>: " + attr.getKey() + '=' + attrVal + "\r\n");
				}
			}

			// 判断request请求是否是post请求
			if (request.method().equals(HttpMethod.POST)) {
				try {
					/**
					 * 通过HttpDataFactory和request构造解码器
					 */
					decoder = new HttpPostRequestDecoder(factory, request);
					boolean readingChunks = HttpUtil.isTransferEncodingChunked(request);
					System.out.println("Is Chunked: " + readingChunks + "\r\n");
					System.out.println("IsMultipart: " + decoder.isMultipart() + "\r\n");
				} catch (ErrorDataDecoderException e1) {
					e1.printStackTrace();
					return;
				}
			}
		}

		if (decoder != null) {
			if (msg instanceof HttpContent) {
				// New chunk is received
				HttpContent chunk = (HttpContent) msg;
				try {
					decoder.offer(chunk);
				} catch (ErrorDataDecoderException e1) {
					e1.printStackTrace();
					ctx.channel().close();
					return;
				}
				try {
					List<InterfaceHttpData> datas = decoder.getBodyHttpDatas();
					for (InterfaceHttpData data : datas) {
						writeHttpData(data);
					}
					// while (decoder.hasNext()) {
					// InterfaceHttpData data = decoder.next();
					// if (data != null) {
					// try {
					// writeHttpData(data);
					// } finally {
					//// data.release();
					// }
					// }
					// }
				} catch (EndOfDataDecoderException e1) {
					e1.printStackTrace();
				}

			}
		}

		if (msg instanceof HttpContent) {
			HttpContent content = (HttpContent) msg;

			ByteBuf buf = content.content();
			System.out.println("content===>" + buf.toString(io.netty.util.CharsetUtil.UTF_8));
			buf.release();

			String res = "HttpContent I am OK";
			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
					Unpooled.wrappedBuffer(res.getBytes("UTF-8")));
			response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
			response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
			if (HttpUtil.isKeepAlive(request)) {
				response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
			}
			ctx.write(response);
			ctx.flush();
		}
	}

	private void writeHttpData(InterfaceHttpData data) throws IOException {
		/**
		 * HttpDataType有三种类型 Attribute, FileUpload, InternalAttribute
		 */
		if (data.getHttpDataType() == HttpDataType.Attribute) {
			Attribute attribute = (Attribute) data;
			String value;
			try {
				value = attribute.getValue();
				System.out.println("value===>" + value + ",dateType:" + attribute.getHttpDataType().name());

			} catch (IOException e1) {
				e1.printStackTrace();
				return;
			}
			if (value.length() > 100) {
				System.out.println("\r\nBODY Attribute: " + attribute.getHttpDataType().name() + ":" + attribute.getName() + " data too long\r\n");
			} else {
				System.out.println("\r\nBODY Attribute===》 (key:" + attribute.getName() + ",value:" + attribute.getValue() + ")==》"
						+ attribute.toString() + "\r\n");
			}
		}
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		cause.printStackTrace();
		ctx.close();
	}

}